using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using MiddlewareServer.Socket;
using System.Net;
using System.Runtime.InteropServices;
using System.Collections;

namespace MiddlewareServer
{
    public class MiddlewareServer : IServer_rpt, IServer_cmd
    {
        IServer_rpt mServer;
        SocketServer mSocketServer;
        Dictionary<IPAddress,int> clientTable;

        public MiddlewareServer(IServer_rpt a_server)
        {
            mSocketServer = new SocketServer(ReadSocketData, connect,disconnect);
            mSocketServer.Connect();
            mServer = a_server;

            clientTable = new Dictionary<IPAddress, int>();
        }

        public void ReadSocketData(IPAddress ip, byte[] data)
        {
            ShootStruct structa = BytesToStruct(data);
            Console.WriteLine("[MS]::ReadSocketData TYP:{0} X:{1},Y:{2}",structa.header.msgType,structa.shootX,structa.shootY);

            //MAPPING

            if (structa.header.msgType == 1)//SHOOT
            {
                mServer.shoot((uint)clientTable[ip], structa.shootX, structa.shootY);
            }
        }

        private ShootStruct BytesToStruct(byte[] dataIn)
        {
            GCHandle hDataIn = GCHandle.Alloc(dataIn, GCHandleType.Pinned);
            ShootStruct ys = (ShootStruct)Marshal.PtrToStructure(hDataIn.AddrOfPinnedObject(),
            typeof(ShootStruct));
            hDataIn.Free();
            return ys;
        }

        # region IServer_rpt Members

        /// <summary>
        /// building connection between client and server using client id
        /// </summary>
        /// <param name="a_uiClientID">client identifier</param>
        public void connect(IPAddress ip)
        {
            Console.WriteLine("[MS]::CONNECT from CID:{0}", ip.ToString());

            if (clientTable.ContainsValue(0) == false)
            {
                clientTable.Add(ip, 0);
            }
            else
            {
                Console.WriteLine("[MS]::CONNECT failed");
            }
           // mServer.connect(a_uiClientID);
        }

        /// <summary>
        /// sending client ships board. Declaration of beeng ready by the client
        /// </summary>
        /// <param name="a_uiClientID">client identifier</param>
        /// <param name="a_dtShipsTable">table with ships placement for individual client</param>
        public void ready(uint a_uiClientID, DataTable a_dtShipsTable)
        {
            Console.WriteLine("[MS]::READY from CID:{0}", a_uiClientID);
        }

        /// <summary>
        /// shot performed by client including shot position
        /// </summary>
        /// <param name="a_uiClientID">client identifier</param>
        /// <param name="a_uiXPos">X shot position</param>
        /// <param name="a_uiYPos">Y shot position</param>
        public void shoot(uint a_uiClientID, uint a_uiXPos, uint a_uiYPos)
        {
            Console.WriteLine("[MS]::SHOT from CID:{0}, X = {1}, Y = {2}", a_uiClientID, a_uiXPos, a_uiYPos);
            //mSocketServer.
        }

        /// <summary>
        /// destroying connection between client and server using client id
        /// </summary>
        /// <param name="uiClientID">client identifier</param>
        public void disconnect(IPAddress ip)
        {
            Console.WriteLine("[MS]::DISCONNECT from CID:{0}", ip.ToString());

            if (clientTable.ContainsKey(ip) == true)
            {
                clientTable.Remove(ip);
            }
        }
        #endregion

        #region IServer_cmd Members

        /// <summary>
        /// result with connection status or error code 
        /// </summary>
        /// <param name="a_eRetCode">error code enum</param>
        public void connectResult(eReturnErrorCode a_eRetCode)
        {
            Console.WriteLine("[MS]::CONNECT RESULT returnValue:{0}", a_eRetCode);
        }
        /// <summary>
        /// result of client board confirmation
        /// </summary>
        /// <param name="a_uiClientID">client identifier</param>
        /// <param name="a_eRetCode">error code enum</param>
        public void readyResult(uint a_uiClientID, eReturnErrorCode a_eRetCode)
        {
            Console.WriteLine("[MS]::READY RESULT from CID:{0}, returnValue: {1}", a_uiClientID, a_eRetCode);
        }
        /// <summary>
        /// result of client shot
        /// </summary>
        /// <param name="a_uiClientID">client identifier</param>
        /// <param name="a_uiXPos">X shot position</param>
        /// <param name="a_uiYPos">Y shot position</param>
        /// <param name="a_uiShooted"></param>
        public void shootResult(uint a_uiClientID, uint a_uiXPos, uint a_uiYPos, uint a_uiShooted)
        {
            Console.WriteLine("[MS]::SHOOT RESULT from CID:{0}, a_uiShooted: {1}", a_uiClientID, a_uiShooted);
            //TODO MAP IP, CLIID
            ShootResStruct shootRes;
            shootRes.header.msgType = 2;
            shootRes.header.msgLength = 20;
            shootRes.shootX = a_uiXPos;
            shootRes.shootY = a_uiYPos;
            shootRes.shootCnt = a_uiShooted;

            byte[] sendPacket = Serialize(shootRes);

            mSocketServer.WriteData(IPAddress.Parse("127.0.0.1"), sendPacket);
        }
        /// <summary>
        /// result of disconnection client from server
        /// </summary>
        /// <param name="a_eRetCode">error code enum</param>
        public void disconnectResult(eReturnErrorCode a_eRetCode)
        { 
            
        }

        #endregion

        public static byte[] Serialize(object obj)
        {
            Type objectType = obj.GetType();
            int objectSize = Marshal.SizeOf(obj);
            IntPtr buffer = Marshal.AllocHGlobal(objectSize);
            Marshal.StructureToPtr(obj, buffer, false);
            byte[] array = new byte[objectSize];
            Marshal.Copy(buffer, array, 0, objectSize);
            Marshal.FreeHGlobal(buffer);
            return array;
        }
    }
}
